(define each
  (native_function "
    Proc.new do |arguments, interpreter|
      list = interpreter.evaluate(arguments[0])
      if list.is_a? Array
        formals = arguments[1]
      elsif list.is_a? Hash
        formals = arguments[1,2]
      end
      body = arguments.slice(2, arguments.length)
    
      raise 'Error: Each function takes a minimum of three arguments!' unless arguments.length > 2
      raise 'Error: Argument one must be a list or hash!' unless list.is_a?(Array) || list.is_a?(Hash)
      raise 'Error: Formal cannot be defined as a string!' if formals.is_a? String
      
      sub_env = Schaefer::Environment.new(interpreter.current_environment)

      executeList = Proc.new do |body, environment, interpreter|
        interpreter.current_environment = environment
        result = nil
        if list.is_a?(Array)
          list.each do |element|
            interpreter.current_environment.define(formals, element)
            body.each do |expression|
              result = interpreter.evaluate(expression)
            end
          end
        else
          list.each do |key, value|
            interpreter.current_environment.define(formals[0], key)
            interpreter.current_environment.define(formals[1], value)
            body.each do |expression|
              result = interpreter.evaluate(expression)
            end
          end
        end
        interpreter.current_environment = environment.parent
        result
      end
      
      executeList.call(body, sub_env, interpreter)
    end
  "))
